﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Hardware.Meter
{
    public class Tuoliduo : IMeter
    {
        /**
        *  001-柯力D2008F(tf=0)
           002-顶松DS822系列
           003-HBM
           004-耀华A9(tf=0)
           999-自定义协议
           005-托利多
        * 
        */
        public bool IsOpen { get; set; }     //端口连接状态

        public int MessageLenth { get; set; }     //消息长度

        public int SleepTime { get; set; }       // 空闲时间

        public bool StickyPackage { get; set; }  // 粘包拆包

        public bool ShowHexFlag { get; set; } = false;      //显示Hex数据，缺省为假

        private byte[] remainData = null;

        public event EventHandle DataReceived;
        public event StatusEventHandle StatusChanged;
        public event EventShowHexData ShowHexData;

        public CommPort MeterSerialPort;

        private MeterParameter meterParamter;

        public Tuoliduo(MeterParameter _param, int _messageLength)
        {
            Settings.Port settings = new Settings.Port();
            settings.baudRate = _param.BaudValue;
            settings.dataBits = _param.DataBits;
            settings.parity = _param.parity;
            settings.stopBits = _param.stopBits;
            settings.portName = _param.ComName;
            MessageLenth = _messageLength;
            meterParamter = _param;
            SleepTime = _param.CharInterval;  //间隔时间
            //StickyPackage = true;

            MeterSerialPort = new CommPort(settings, SleepTime);
            MeterSerialPort.StatusChanged += Meter_StatusChanged;
            MeterSerialPort.DataReceived += Meter_DataReceived;

        }

        public void Open()
        {
            try
            {
                MeterSerialPort.Open();
                IsOpen = MeterSerialPort.IsOpen;
                StatusChanged?.Invoke($"仪表连接:{meterParamter.ComName} {meterParamter.BaudValue} 成功!", this);
            }
            catch (Exception ex)
            {
                IsOpen = false;
                StatusChanged?.Invoke($"连接仪表:{meterParamter.ComName} {meterParamter.BaudValue} 异常:{ex.Message}", this);
            }
        }


        /// <summary>
        /// 关闭仪表
        /// </summary>
        public void Close()
        {
            if (MeterSerialPort != null)
            {
                if (IsOpen) MeterSerialPort.Close();
                MeterSerialPort = null;
            }
        }

        /// <summary>
        /// 根据不同的仪表，在此进行拆解出来，返回到前台
        /// 
        /// </summary>
        /// <param name="readBuffer"></param>
        /// <param name="sender"></param>
        private void Meter_DataReceived(byte[] readBuffer)
        {
            try
            {
                // 如果显示 Hex，发送 Hex 到仪表显示框中
                if (ShowHexFlag)
                {
                    ShowHexData?.Invoke(Utils.ByteArr2HexString(readBuffer));
                }
                // 分析接收到的数据
                AnalizeData(readBuffer);
            }
            catch (Exception ex)
            {               
                StatusChanged?.Invoke($"接收到仪表数据错误:{ex.Message}", this);
            }
        }

        private void Meter_StatusChanged(string param)
        {
            StatusChanged?.Invoke(param, this);
        }

        private int Find(byte[] data, byte target, int startIndex = 0, int len = -1)
        {
            try
            {
                for (int i = startIndex; i < data.Length; i++)
                {
                    if (data[i] == target)
                        return i;
                }
                return -1;
            }
            catch (Exception ex)
            {
                Debug.Print("Find:" + ex.Message);
                return -1;
            }
        }

        /// <summary>
        /// 分析仪表数据
        /// 3、串行通讯发送的重量数据为ASCI码，每次发送12个字节
        ///其定义如下:
        ///第1字节:起始位(02H)
        ///状态字 A第2字节:
        ///第3字节:状态字 B
        ///第4字节:状态字C
        ///第5字节:6位重量值的高位
        ///第10字节:6位重量值的低位
        ///第11字节:回车(0DH)
        ///第12字节:换行(0AH)
        /// </summary>
        /// <param name="source"></param>
        private void AnalizeData(byte[] source)
        {
            try
            {
                if (DataReceived == null || source == null || source.Length == 0)
                    return;

                // 合并残留数据
                byte[] combinedData = remainData != null ?
                    Utils.AddBytesTwo(remainData, source) :
                    source;
                remainData = null;  // 清空残留数据

                int startIndex = 0;
                while (startIndex < combinedData.Length)
                {
                    // 查找起始位(0x02)
                    int startPos = Find(combinedData, 0x02, startIndex);
                    if (startPos < 0) break;  // 未找到有效起始位

                    // 检查是否满足最小长度
                    if (startPos + MessageLenth > combinedData.Length)
                    {
                        remainData = new byte[combinedData.Length - startPos];
                        Array.Copy(combinedData, startPos, remainData, 0, remainData.Length);
                        break;
                    }

                    // 验证结束标志
                    if (combinedData[startPos + 10] != 0x0D ||
                        combinedData[startPos + 11] != 0x0A)
                    {
                        startIndex = startPos + 1;  // 跳过无效起始位
                        continue;
                    }

                    // 提取完整数据包
                    byte[] packet = new byte[MessageLenth];
                    Array.Copy(combinedData, startPos, packet, 0, MessageLenth);

                    // 处理有效数据包
                    DataReceived?.Invoke(TuoliduoProtocal(packet), this);

                    // 移动处理位置
                    startIndex = startPos + MessageLenth;
                }

                // 保存尾部残留数据（非StickyPackage模式时不保留）
                if (StickyPackage && startIndex < combinedData.Length)
                {
                    remainData = new byte[combinedData.Length - startIndex];
                    Array.Copy(combinedData, startIndex, remainData, 0, remainData.Length);
                }
            }
            catch (Exception)
            {

            }
        }


        /// <summary>
        /// 分析托利多的数据
        /// 状态字 A 第2字节
        ///D7 0
        ///D6 0
        ///D5 1
        ///D4 0
        ///D3 0
        ///D2
        ///D1
        ///D0
        ///小数点: X .X .XX .XXX .XXXX .XXXXX
        ///D2 =    0  0  1   1     1     1  
        ///D1 =    0  1  0   0     1     1
        ///D0 =    0  1  0   1     0     1
        ///状态字 B  第3字节
        ///D7 0
        ///D6 0
        ///D5 1
        ///D4 1
        ///D3 0非动态，1为动态
        ///D2 0正常，1超载
        ///D1 0为正，1为负
        ///D0 0        
        /// </summary>
        /// <param name="_buffer"></param>
        /// <returns></returns>

        private double TuoliduoProtocal(byte[] _buffer)
        {
            if (_buffer.Length != MessageLenth) return 0;

            try
            {
                byte firstFlag = _buffer[0];
                byte enterFlag = _buffer[10];
                byte lastFlag = _buffer[11];
                StatusChanged?.Invoke("正在分析仪表数据:" + Utils.ByteArr2HexString(_buffer), this);
                if (firstFlag.ToString("X2") == "02" 
                    && enterFlag.ToString("X2") == "0D"
                    && lastFlag.ToString("X2") == "0A")
                {
                    int pt = Convert.ToInt32(_buffer[1]);  //状态字 A 
                    int negativeFlag = Convert.ToInt32(_buffer[2]);  //状态字 B
                    //十六进制转成二进制
                    string dec = Convert.ToString(pt, 2);                        //转为2进制
                    string negativeFlagStr = Convert.ToString(negativeFlag, 2);  //转为2进制
                    string dotFlagStr = dec.Substring(dec.Length - 3);//判断小数点在第几位  
                    string negative = negativeFlagStr.Substring(negativeFlagStr.Length - 2, 1); //取倒数第二位
                    //重量
                    byte[] buff = new byte[6];
                    Array.Copy(_buffer, 4, buff, 0, 6);
                    //根据 dotFlag 判断小数点位置
                    var WeightMessagetmp = Encoding.Default.GetString(buff);  
                    decimal d_weight = 0;
                    int dotFlag = Convert.ToInt32(dotFlagStr, 2);                    
                    if (dotFlag > 0) dotFlag -= 2;
                    if(dotFlag > 0)
                    {
                        d_weight = Convert.ToDecimal(WeightMessagetmp.Substring(0, 6 - dotFlag) + "." + WeightMessagetmp.Substring(6 - dotFlag, dotFlag));
                    }
                    else
                    {
                        d_weight = Convert.ToDecimal(WeightMessagetmp);
                    }
                    // 判断实际重量
                    if (d_weight != 0)
                    {
                        if (negative.Equals("0"))
                        {
                            return Utils.MeterUnitChange(Convert.ToDouble(d_weight), meterParamter.MeterUnit, meterParamter.SystemUnit);
                        }
                        else
                        {
                            // 返回负值
                            return Utils.MeterUnitChange(Convert.ToDouble(-d_weight), meterParamter.MeterUnit, meterParamter.SystemUnit);
                        }
                        
                    }
                    else
                    {
                        return 0;
                    }
                }
                else
                {
                    return 0;
                }
            }
            catch (Exception ex)
            {
                StatusChanged?.Invoke("托利多仪表接收数据异常:" + ex.Message, this);
                return 0;
            }
        }
    }
}
